varying vec4 PositionES;  // vertex position in eye space
varying vec3 NormalES;
varying vec3 Ray_O;
varying vec3 Ray_D;

uniform sampler3D volTex;
uniform sampler2D testTex;

int               steps = 128;
//uniform float stepsize = 0.1,
float             brightness = 1.0;
float             density = 0.03;
float             threshold = 0.99;
vec3              boxMin = { -1.0, -1.0, -1.0f };
vec3              boxMax = { 1.0, 1.0, 1.0f };

// calculate intersection between ray and box
// http://www.siggraph.org/education/materials/HyperGraph/raytrace/rtinter3.htm
bool IntersectBox(vec3 ray_orig, 
                  vec3 ray_dir,
                  vec3 boxmin, 
                  vec3 boxmax, 
                  out float tnear, 
                  out float tfar)
{
    // compute intersection of ray with all six bbox planes
    vec3 invR = 1.0 / ray_dir;
    vec3 tbot = invR * (boxmin.xyz - ray_orig);
    vec3 ttop = invR * (boxmax.xyz - ray_orig);

    // re-order intersections to find smallest and largest on each axis
    vec3 tmin = min (ttop, tbot);
    vec3 tmax = max (ttop, tbot);

    // find the largest tmin and the smallest tmax
    vec2 t0 = max (tmin.xx, tmin.yz);
    float largest_tmin = max (t0.x, t0.y);
    t0 = min (tmax.xx, tmax.yz);
    float smallest_tmax = min (t0.x, t0.y);

    // check for hit
    bool hit;
    if ((largest_tmin > smallest_tmax)) 
        hit = false;
    else
        hit = true;

    tnear = largest_tmin;
    tfar = smallest_tmax;

    return hit;
}

#define FRONT_TO_BACK

// fragment program
void main()
{
    //gl_FragColor = 0.5; //normalize(NormalES);
    //return;

    float stepsize = 1.7 / steps;

    vec3 ray_dir = normalize(Ray_D); 
    //ray_dir = normalize(ray_dir);

    // calculate ray intersection with bounding box
    float tnear, tfar;

    vec3 ray_orig = Ray_O;

    //gl_FragColor = vec4(ray_dir, 1);
    //return;

    bool hit = IntersectBox(ray_orig, ray_dir, boxMin, boxMax, tnear, tfar);
    if (!hit) discard;
    else
    {
        gl_FragColor = vec4(1, 1, 1, 1);
        //return;
    }
    if (tnear < 0.0) tnear = 0.0;

    // calculate intersection points
    vec3 Pnear = ray_orig + ray_dir*tnear;
    vec3 Pfar = ray_orig + ray_dir*tfar;
    // convert to texture space
    Pnear = Pnear*0.5 + 0.5;
    Pfar  = Pfar *0.5 + 0.5;
    
    // march along ray, accumulating color
    vec4 c = 0;

#ifdef FRONT_TO_BACK
    // use front-to-back rendering
    vec3 P = Pnear;
    vec3 Pstep = ray_dir * stepsize;
#else
    // use back-to-front rendering
    vec3 P = Pfar;
    vec3 Pstep = -ray_dir * stepsize;
#endif

    for(int i=0; i<steps; i++) 
    {
        vec4 s = texture3D(volTex, P);

        s = abs(s);
        s.a = clamp(s.a, 0.0, 1.0);
        s.a *= density;

#ifdef FRONT_TO_BACK
        s.rgb *= s.a;   // premultiply alpha
        c = (1 - c.a)*s + c;
        // early exit if opaque
        if (c.a > threshold)
            break;
#else
        c = lerp(c, s, s.a);
#endif

        P += Pstep;
    }
    c.rgb *= brightness;

    gl_FragColor = c;
//    return (tfar - tnear);
//    return hit;
}
